package com.study.spmongodb.prize;

import com.study.spmongodb.prize.config.ApiResult;
import com.study.spmongodb.prize.config.RedisKeys;
import com.study.spmongodb.prize.entity.CardGame;
import com.study.spmongodb.prize.entity.CardProduct;
import com.study.spmongodb.prize.entity.CardUser;
import com.study.spmongodb.prize.utils.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

/**
 * @author study
 * @version 1.0
 * @date 2020/10/9 21:17
 */
@RestController
@RequestMapping("/api/act")
@Api(tags = {"抽奖模块"})
public class ActController {

    @Autowired
    private RedisUtil redisUtil;


    @GetMapping("/go/{gameid}")
    @ApiOperation(value = "抽奖")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "gameid", value = "活动id", example = "1", required = true)
    })
    public ApiResult<Object> act(@PathVariable int gameid, HttpServletRequest request) {
        Date now = new Date();
        //获取活动基本信息
        CardGame game = (CardGame) redisUtil.get(RedisKeys.INFO + gameid);

        //判断活动是否开始
        //如果活动信息没有加载到redis，无效
        //如果活动以加载，预热完成，但是开始 > 当前时间 ，无效
        if (game == null || game.getStarttime().after(now)) {
            return new ApiResult(-1, "活动未开始", now);
        }
        //判断活动是否结束
        if (game.getEndtime().before(now)) {
            return new ApiResult(-1, "活动已经结束", null);
        }
        //获取当前用户
        final HttpSession session = request.getSession();
        CardUser user = (CardUser) redisUtil.get(RedisKeys.SESSIONID + session.getId());
        if (user == null) {
            return new ApiResult(-1, "未登录", null);
        } else {
            if (!redisUtil.hasKey(RedisKeys.USERGAME + user.getId() + "_" + gameid)) {
                redisUtil.set(RedisKeys.USERGAME + user.getId() + "_" + gameid, 1, (game.getEndtime().getTime() - now.getTime()) / 1000);
                //TODO 持久化抽奖记录，扔给消息服务器
            }
        }

        //用户已经中奖次数
        Integer count = (Integer) redisUtil.get(RedisKeys.USERHIT + gameid + "_" + user.getId());
        if (count == null) {
            count = 0;
            redisUtil.set(RedisKeys.USERHIT + gameid + "_" + user.getId(), count, (game.getEndtime().getTime() - now.getTime()) / 1000);
        }
        //根据会员等级，获取本活动允许的最大中奖数
        Integer maxcount = (Integer) redisUtil.hget(RedisKeys.MAXGOAL + gameid, user.getLevel() + "");
        //如果没设置，默认为0，即：不限制次数
        maxcount = maxcount == null ? 0 : maxcount;
        //次数对比
        if (maxcount > 0 && count >= maxcount) {
            //如果达到最大次数，不允许抽奖
            return new ApiResult(-1, "您已达到最大中奖数", null);
        }

        //TODO 以下需要分布式锁，避免 令牌 因为多线程 导致令牌顺序混乱
        //以上校验全部通过，准许进入抽奖逻辑
        Long token = (Long) redisUtil.leftPop(RedisKeys.TOKENS + gameid);
        if (token == null) {
            //令牌已经用完，奖品抽光了
            return new ApiResult(-1, "奖品已抽光", null);
        }

        //判断令牌时间戳大小，即是否中奖
        if (now.getTime() < token / 1000) {
            //当前时间小于令牌时间戳，说明未到发放时间点，放回令牌 返回未中奖
            redisUtil.leftPush(RedisKeys.TOKENS + gameid, token);
            return new ApiResult(0, "未中奖", null);
        }

        //以上逻辑走完，说明中奖了
        //抽中的奖品：
        CardProduct product = (CardProduct) redisUtil.get(RedisKeys.TOKEN + gameid + "_" + token);
        //中奖次数加1
        redisUtil.incr(RedisKeys.USERHIT + gameid + "_" + user.getId(), 1);
        //投放消息给队列，中奖后的耗时业务，交给消息模块处理
        //返回给前台中奖信息
        return new ApiResult(1, "恭喜中奖", product);
    }
}
